#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <queue>
#include <pthread.h>

namespace ns_thread_pool
{
    const int g_num = 5;
    template <class T>
    class Thread_pool
    {
    private:
        int num_;                 // 线程数
        std::queue<T> task_queue; // 任务队列，临界资源

        pthread_mutex_t mtx;
        pthread_cond_t cond;

        static Thread_pool<T> *ins;

        Thread_pool(int num = g_num) : num_(num)
        {
            pthread_mutex_init(&mtx, nullptr);
            pthread_cond_init(&cond, nullptr);
        }
        Thread_pool(const Thread_pool<T> &tp) = delete;
        Thread_pool<T> &operator=(Thread_pool<T> &tp) = delete;

    public:
        static Thread_pool<T> *GetInstance()
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
            
            if (ins == nullptr)
            {//双判定，减少锁的争用，提高获取单例的效率
                if (ins == nullptr)
                { // 当前单例对象还没被创建
                    pthread_mutex_lock(&lock);
                    ins = new Thread_pool<T>();
                    ins->InitThreadPool();
                    std::cout << "首次加载对象" << std::endl;
                }
                pthread_mutex_unlock(&lock);
            }

            return ins;
        }

        // 在类中要让线程执行类内成员方法是不可行的。
        // 只能让线程执行静态方法
        static void *Rountine(void *args)
        {
            pthread_detach(pthread_self()); // 线程分离
            Thread_pool<T> *tp = (Thread_pool<T> *)args;
            while (true)
            {
                tp->Lock();
                while (tp->IsEmpty())
                { // 任务队列为空
                    tp->wait();
                }
                // 任务队列中一定有任务了
                T t;
                tp->PopTask(&t);
                tp->UnLock();

                t();
            }
        }
        void InitThreadPool()
        {
            pthread_t tid;
            for (int i = 0; i < num_; i++)
            {
                pthread_create(&tid, nullptr, Rountine, (void *)this);
            }
        }
        void Lock()
        {
            pthread_mutex_lock(&mtx);
        }
        void UnLock()
        {
            pthread_mutex_unlock(&mtx);
        }
        bool IsEmpty()
        {
            return task_queue.empty();
        }
        void wait()
        {
            pthread_cond_wait(&cond, &mtx);
        }
        void WakeUp()
        {
            pthread_cond_signal(&cond);
        }
        void PushTask(const T &in)
        {
            Lock();
            task_queue.push(in);
            UnLock();
            WakeUp();
        }
        void PopTask(T *out)
        {
            *out = task_queue.front();
            task_queue.pop();
        }
        ~Thread_pool()
        {
            pthread_mutex_destroy(&mtx);
            pthread_cond_destroy(&cond);
        }
    };

    template <class T>
    Thread_pool<T> *Thread_pool<T>::ins = nullptr;
}